package com.fili.core.sources;

import com.fili.core.utils.PathTrimmer;

import java.util.ArrayList;
import java.io.*;

/**
 * Created by Claudiu-Florin FILIMON
 * Date: Nov 16, 2006
 * Time: 4:15:18 PM
 * Revision: 0
 */
public class SourceMapper
{
    private String sourcePath;
    private int bigFile;
    private String[] mappedFiles;
    private LocationMapping[] mappings;
    private MappedSource[] mappedSources;


    public MappedSource[] getMappedSources()
    {
        return mappedSources;
    }

    public String getSourcePath()
    {
        return sourcePath;
    }

    /**
     * Creates a new <i>SourceMapper</i> with index <i>bigFile</i> and source file <i>sourcePath</i>
     *
     * @param bigFile    the bigFile index
     * @param sourcePath the bigFile source
     * @throws IOException throwed if the file cannot be found or cannot be read
     */
    public SourceMapper(int bigFile, String sourcePath) throws IOException
    {
        this.sourcePath = sourcePath;
        this.bigFile = bigFile;
        parseFile();
    }

    /**
     * Obtains the bigFile location where <i>smallFile</i>@<i>smallLine</i> is written.
     *
     * @param smallFile the smallFile index
     * @param smallLine the line in the smallFile
     * @return the mapping
     */
    public LocationMapping mapFrom(int smallFile, int smallLine)
    {
        for (int i = 0; i < mappings.length; i++)
            if ((mappings[i].getSmallFile() == smallFile) && (mappings[i].getSmallLine() == smallLine))
                return mappings[i];
        return null;
    }

    /**
     * Obtains the <i>smallFile</i> and <i>smallLine</i> where this line from the <i>bigFile</i> maps to.
     *
     * @param bigLine the line in the bigfile
     * @return the location of the mapping
     */
    public LocationMapping mapTo(int bigLine)
    {
        for (int i = 0; i < mappings.length; i++)
            if (mappings[i].getBigLine() == bigLine)
                return mappings[i];
        return null;
    }

    private void parseLine(int n, String line, ArrayList files, ArrayList maps)
    {
        int p = line.length();
        int i;
        int pos;
        String src;
        while (true)
        {
            if (p < 7)
                return;
            if (!line.substring(p - 7, p).equals(":ERROR:"))
                return;
            p -= 8;
            if (line.charAt(p) != ')')
                return;
            i = p;
            while (line.charAt(i) != '(')
                i--;
            pos = Integer.parseInt(line.substring(i + 1, p));
            p = i;
            while ((line.charAt(i) != '/') && (line.charAt(i - 1) != '/'))
                i--;
            src = line.substring(i, p);
            p = i - 2;

            i = files.indexOf(src);
            if (i < 0)
            {
                files.add(src);
                i = files.size() - 1;
            }

            maps.add(new LocationMapping(bigFile, i, pos));
        }
    }

    private void parseFile() throws IOException
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(sourcePath)));
        ArrayList files = new ArrayList();
        ArrayList maps = new ArrayList();

        String line;
        int pos = 1;

        while ((line = br.readLine()) != null)
        {
            parseLine(pos++, line, files, maps);
        }

        mappedFiles = new String[files.size()];
        for (int i = 0; i < mappedFiles.length; i++)
            mappedFiles[i] = (String) files.get(i);

        files.clear();

        mappings = new LocationMapping[maps.size()];
        for (int i = 0; i < mappings.length; i++)
            mappings[i] = (LocationMapping) maps.get(i);

        maps.clear();

        mappedSources = new MappedSource[mappedFiles.length];
        for (int i = 0; i < mappedFiles.length; i++)
        {
            mappedSources[i] = new MappedSource(i, mappedFiles[i], this);
        }
    }

    public String toString()
    {
        return PathTrimmer.getFileName(sourcePath);
    }
}
